/*
* ==============================================================================
*  Name        : gamecontroller.cpp
*  Part of     : OpenC / OpenCOpenglEx
*  Interface   : 
*  Description : Contains the implementations of CGameController
*                & CWsEventReceiver.
*  Version     : 
*
*  Copyright (c) 2007 Nokia Corporation.
*  This material, including documentation and any related 
*  computer programs, is protected by copyright controlled by 
*  Nokia Corporation.
* ==============================================================================
*/
#include "game.h"
#include "gamecontroller.h"
#include <coemain.h> // for CCoeEnv

#include "symbian_memoryhandler.h"
#include "string.h"
#include "gpuPrim.h"
#include <stdio.h>
#include <stdlib.h>
#include "psxCommon.h"

#include "gpuPlugin.h"
#include "spu.h"
#include "system.h"
#include "misc.h"
#include "R3000a.h"

//extern R3000Acpu* psxCpu;
// -----------------------------------------------------------------------------
// CGameController::NewLC
// The Factory Function for a CGameController object.
// -----------------------------------------------------------------------------
//

extern CGameController* gameController;
extern short int toggle_button_map[16];

TBool iIsPause = EFalse;

extern int iFilter;
extern char IsoFile[1024];
//PsxConfig Config;

PcsxConfig Config;
R3000Acpu *psxCpu;
psxRegisters* psxRegs;
u32 *psxMemWLUT;
u32 *psxMemRLUT;
cdrStruct cdr;
long LoadCdBios;
s8 *psxH;
s8 *psxR;
s8 *psxP;
s8 *psxM;
psxCounter psxCounters[5];
unsigned long psxNextCounter, psxNextsCounter; 

char packfile[256];
char gamepath[256] = "E:\\data\\pcsx\\";
char gamedir[256] = "E:\\data\\pcsx\\games\\";
char pathfile[256] = "E:\\data\\pcsx\\game.path";
char configfile[256] = "E:\\data\\pcsx\\default.cfg";


//prototypes
s32 InitComponents(void);
void SysPrintf(char *fmt, ...);

CGameController* CGameController::NewLC( EGLDisplay aEglDisplay )
{
    CGameController* self = new (ELeave) CGameController( aEglDisplay );
    
    CleanupStack::PushL( self );
    
    self->ConstructL();

    return self;    
}

// -----------------------------------------------------------------------------
// CGameController::CGameController
// Constructor.
// -----------------------------------------------------------------------------
//
CGameController::CGameController( EGLDisplay aEglDisplay )
                :iEglDisplay( aEglDisplay ),
                 iEglSurface( NULL ),
                 iEglContext( NULL ),
                 iWindow( NULL ),
                 iWsEventReceiver( NULL ),
                 iGame( NULL ),
                 iWsScreenDevice( NULL ),
                 iIsAppInFocus( EFalse ),
                 iIsVisible( ETrue )
{
}

// -----------------------------------------------------------------------------
// CGameController::~CGameController
// Destructor.
// -----------------------------------------------------------------------------
//
CGameController::~CGameController()
{
    // EGL related cleanup.
    eglMakeCurrent( iEglDisplay, EGL_NO_SURFACE, 
                    EGL_NO_SURFACE, EGL_NO_CONTEXT 
                  );
    eglDestroySurface( iEglDisplay, iEglSurface );
    eglDestroyContext( iEglDisplay, iEglContext );
    
    // Destroy the RWindow.
    if( iWindow != NULL )
    {
        iWindow->SetOrdinalPosition( KOrdinalPositionSwitchToOwningWindow );
        iWindow->Close();
        delete iWindow;
        iWindow = NULL;
    }
    
    delete iWsEventReceiver;
}

// -----------------------------------------------------------------------------
// CGameController::ConstructL
// Second phase constructor.
// Initializes EGL.
// -----------------------------------------------------------------------------
//
void CGameController::ConstructL()
{    
    CCoeEnv* env = CCoeEnv::Static();
    if( !env )
    {
        User::Leave( KErrCoeEnvNotInitialized );
    }

    // Get the Windows Server Session, screen device and window group.
    iWsSession = env->WsSession();
    iWsScreenDevice = env->ScreenDevice();
    iWindowGroup = env->RootWin();
    if( !iWsScreenDevice )
    {
        User::Leave( KErrCoeEnvNotInitialized );
    }

    // Intializes iWindow to a full screen window.
    CreateNativeWindowL();
    
    // Choose the buffer size based on the Window's display mode.
    TDisplayMode displayMode = iWindow->DisplayMode();
    TInt bufferSize = 0;

    switch( displayMode )
    {
        case(EColor4K):
            bufferSize = 12;
            break;
        case(EColor64K):
            bufferSize = 16;
            break;
        case(EColor16M):
            bufferSize = 24;
            break;
        case(EColor16MU):
	    case(EColor16MA):
            bufferSize = 32;
            break;
        default:
            break;
    }
             
    // Set the desired properties for the EGLSurface
    const EGLint attributeList[] = { 
                                     EGL_SURFACE_TYPE, EGL_WINDOW_BIT, 
                                     EGL_BUFFER_SIZE, bufferSize, 
                                     EGL_NONE 
                                   };
    EGLConfig bestConfig;
    EGLint numConfigs = 0;

    // Choose the best EGLConfig that matches the desired properties. 
    if( eglChooseConfig( iEglDisplay, attributeList, &bestConfig,
                          1, &numConfigs
                        ) == EGL_FALSE
      )
    {
        User::Leave( KErrConfigFailed );
    }
    
    if( numConfigs == 0 )
    {
    	User::Leave( KErrConfigFailed );
    }
        
    // Create a window surface where the graphics are blitted.
    // Pass the Native Window handle to egl.
    iEglSurface = eglCreateWindowSurface( iEglDisplay, bestConfig, 
                                          (void*)iWindow, NULL 
                                        );
    if( iEglSurface == NULL )
    {
        User::Leave( KErrCreateWindowSurfaceFailed );
    }
        
    // Create a rendering context
    iEglContext = eglCreateContext( iEglDisplay, bestConfig,
                                    EGL_NO_CONTEXT, NULL 
                                  );
    if( iEglContext == NULL )
    {
        User::Leave( KErrCreateContextFailed );    
    }
    
    // Make it the current context.
    if( eglMakeCurrent( iEglDisplay, iEglSurface, 
                         iEglSurface, iEglContext 
                      ) == EGL_FALSE
      )
    {
        User::Leave( KErrSetContextFailed );        
    }
    
    // Creates the Active Object that waits for Windows Server events.
    iWsEventReceiver = CWsEventReceiver::NewL( *this );
}

void CGameController::Load()
{

}

void CGameController::Save()
{

}

#define writeln(x) printf(x);printf("\n")

int LoadGameName()
{
FILE *file = fopen(pathfile,"r");
if (file == NULL)
return -1;
fgets(packfile,256,file);
fclose(file);
if (packfile=="")
return -1;
return 0;
}

void LoadConfig(char* configName)
{
char fileName[256];
if (configName == NULL)
sprintf(fileName,"%s%s",gamepath,"default.cfg");
else
sprintf(fileName,"%s%s%s",gamedir,configName,".cfg");
	
FILE *file = fopen(fileName,"r");
if (file == NULL)
{
	printf("Config not found: ",fileName,"\n");
	return;
}
int c;
for (int tmpi = 0; tmpi<16; tmpi++)
{
	c = fgetc(file);
	if (c=='1')
		toggle_button_map[tmpi]=1;
		else
		toggle_button_map[tmpi]=0;
}

if (fgetc(file) == '1')
	iFilter = GL_LINEAR;
else
	iFilter = GL_NEAREST;

if (fgetc(file) == '1')
Config.HLE = 0;
else
Config.HLE = 1;

fclose(file);
}

// -----------------------------------------------------------------------------
// CGameController::StartGameL
// Intializes the Game and Starts the game loop.
// -----------------------------------------------------------------------------
//
void CGameController::StartGameL( CGame& aGame )
{   
	User::SetFloatingPointMode(EFpModeRunFast);
    iGame = &aGame;   
    
    // Allow the game to initialize itself.
    // The opengl es state intialization is done here.
    iGame->Initialize( iWindow->Size().iWidth, iWindow->Size().iHeight );
    
    surface = iEglSurface;
    display = iEglDisplay;
    
	writeln("EQ PCSX");
	writeln("-------");
	writeln("Initialization...");
	
	create_all_translation_caches();
	
#if defined(__SYMBIAN32__)
	sprintf(gamepath, "E:\\data\\PCSX\\");
#endif
	LoadGameName();
	sprintf((char*)IsoFile,"%s%s",gamedir,packfile);

//	memset(&Config, 0, sizeof(PsxConfig));
	Config.PsxAuto = 1;
	Config.Cdda = 1;
	Config.Xa = 1;
#ifdef DYNAREC
	Config.Cpu = 0;
#else
	Config.Cpu = 1;
#endif

#ifdef WITH_HLE
	// Testing HLE?
	Config.HLE = 0;
#else
	// HLE OFF
	Config.HLE = 0;
#endif

	Config.Mdec = 0;
	Config.PsxOut = 0;
	Config.PsxType = 0;
	Config.QKeys = 0;
	Config.RCntFix = 0;
	Config.Sio = 0;
	Config.SpuIrq = 0;
	Config.VSyncWA = 0;

	LoadConfig(NULL);
	
	LoadConfig(packfile);

	if (Config.HLE == 1)
	{
		sprintf((char*)Config.Bios,"%s","nobios");
	}
	
	sprintf((char*)Config.BiosDir, "%sbios\\", gamepath);
	sprintf((char*)Config.Bios, "scph1001.bin");
	sprintf((char*)Config.Mcd1, "%s\\memcards\\mcd001.mcr", gamepath);
	sprintf((char*)Config.Mcd2, "%s\\memcards\\mcd002.mcr", gamepath);
	
	LoadCdBios = 0;

	writeln("SysInit...");
	
	if (SysInit() == -1)
		{
		writeln("ERROR INIT!\nPress any key to exit.");
		getchar();
		return;
		}

	writeln("InitComponents...");
	
	if (InitComponents() == -1)
		{
		writeln("ERROR COMPONENTS!\nPress any key to exit.");
		getchar();
		return;
		}
	
	writeln("SysReset...");

	SysReset();

	writeln("CheckCDRom...");

	//CheckCdrom();

	writeln("LoadCDRom...");

	if (LoadCdrom() == -1)
		{
			writeln("ERROR LOAD CDROM!\nPress any key to exit.");
			getchar();
			return;
		}


    iWindow->SetOrdinalPosition(0);
    iWindowGroup.SetOrdinalPosition(0);

    writeln("EXECUTE!");
//    iIsPause = EFalse;
	psxCpu->Execute();
    aGame.Cleanup();    
}

// -----------------------------------------------------------------------------
// CGameController::ProcessBackgroundTasks
// Calls the RunL on all Active Objects which have 
// pending requests.
// If aIsBlocking is ETrue, this API will block till an event occurs.
// -----------------------------------------------------------------------------
//
void CGameController::ProcessBackgroundTasks( TBool aIsBlocking )
{
    RThread thread;    
    TInt error = KErrNone;
    
    if ( aIsBlocking && !thread.RequestCount() )
    {
        // Block for a event.
        User::WaitForAnyRequest();

        // Run the Active Object corresponding to the event
        CActiveScheduler::RunIfReady( error, CActive::EPriorityIdle );
    }
    
    // Processes all outstanding requests
    while( thread.RequestCount() ) 
    {
        // Processes an event.        
        CActiveScheduler::RunIfReady( error, CActive::EPriorityIdle );
        
        // Decreases thread.RequestCount
        User::WaitForAnyRequest();
    }
}

// -----------------------------------------------------------------------------
// CGameController::CreateNativeWindowL
// Create a full screen RWindow and enables screen size
// change events.
// -----------------------------------------------------------------------------
//
void CGameController::CreateNativeWindowL()
{      
    iWindow = new (ELeave) RWindow( iWsSession );
    
    // Construct the window.
    TInt err = iWindow->Construct( iWindowGroup,
                                   reinterpret_cast<TUint32>( this ) 
                                 );
    User::LeaveIfError( err );

    // Enable the EEventScreenDeviceChanged event.
    iWindowGroup.EnableScreenChangeEvents();                                      
        
    TPixelsTwipsAndRotation pixnrot; 
    iWsScreenDevice->GetScreenModeSizeAndRotation( 
                                iWsScreenDevice->CurrentScreenMode(),
                                pixnrot );
        
    // Set size of the window (cover the entire screen)
    iWindow->SetExtent( TPoint( 0, 0 ),
                        pixnrot.iPixelSize
                      );
                       
    iWindow->SetRequiredDisplayMode( iWsScreenDevice->DisplayMode() );
    
    // Activate window and bring it to the foreground
    iWindow->Activate();
    iWindow->SetVisible( ETrue );
    iWindow->SetNonFading( ETrue ); 
    iWindow->SetShadowDisabled( ETrue ); 
    iWindow->EnableRedrawStore( EFalse ); 
    iWindow->EnableVisibilityChangeEvents();
    iWindow->SetNonTransparent(); 
    iWindow->SetBackgroundColor(); 
    iWindow->SetOrdinalPosition( 0 );    
}

// -----------------------------------------------------------------------------
// CGameController::HandleWsEvent
// This function is called by the CWsEventReceiver 
// Active Object, whenever it receives a Windows Server
// event.
// -----------------------------------------------------------------------------
//
void CGameController::HandleWsEvent( const TWsEvent& aWsEvent )
{
    TInt eventType = aWsEvent.Type();
     
    // Handle Key and Screen Size change Events.
    switch( eventType )
    {
        case EEventKeyDown:
        {
        if (aWsEvent.Key()->iModifiers & EModifierShift)
        	{
        	if (aWsEvent.Key()->iScanCode == '4')
        		{
					if (PsxCycleMult>2)
						{
							PsxCycleMult = PsxCycleMult - 1;
						}
        		}
        	else
			if (aWsEvent.Key()->iScanCode == '6')
				{
					PsxCycleMult = PsxCycleMult + 1;
				}
			else
			if (aWsEvent.Key()->iScanCode==EStdKeyDevice1)
				{
					psxShutdown();
					break;
				}
        	}

        else
		if( iGame )
        iGame->HandleKeyEvent( aWsEvent.Key()->iScanCode, EFalse );
        break;            
        }
        case EEventKeyUp:
        {
            if( iGame )
                iGame->HandleKeyEvent( aWsEvent.Key()->iScanCode, ETrue );
            
            break;            
        }        
        case( EEventScreenDeviceChanged ): // The screen size has changed.
        {
            TPixelsTwipsAndRotation pixnrot; 
            iWsScreenDevice->GetScreenModeSizeAndRotation( 
                                  iWsScreenDevice->CurrentScreenMode(),
                                  pixnrot 
                                                         );       
            if( pixnrot.iPixelSize != iWindow->Size() )
            {
                 
                // Update the window.
                iWindow->SetExtent( TPoint( 0, 0 ),
                                    pixnrot.iPixelSize
                                  );                
                                        
                // If a game is running, notify it about the change.
                if( iGame )
                {
                    iGame->SetScreenSize( pixnrot.iPixelSize.iWidth,
                                          pixnrot.iPixelSize.iHeight 
                                        );                    
                    
                    // Call eglSwapBuffers after the window size has changed.
                    // This updates the window size used by egl. 
                    eglSwapBuffers( iEglDisplay, iEglSurface );                                        
                }                
                                
            }                    
            break;            
        }
        case EEventFocusLost: 
        {
            iIsAppInFocus = EFalse;
//            iIsPause = ETrue;
            break;
        }
        case EEventFocusGained:
        {
            iIsAppInFocus = ETrue;
            break;
        }
        case EEventWindowVisibilityChanged:
        {
            // Check if the event is for the iWindow
            if( aWsEvent.Handle() ==
                        reinterpret_cast<TUint32>( this )
                  
              )
            {
                if( aWsEvent.VisibilityChanged()->iFlags &
                    TWsVisibilityChangedEvent::ECanBeSeen 
                )                
                {
                      iIsVisible = ETrue;
                }
                else
                {
                      iIsVisible = EFalse;
//                      iIsPause = ETrue;
                }
                
            }                            
            break;
        }
        case EEventNull:
        case EEventKey:        
        case EEventUser:                                
        case EEventWindowGroupListChanged:
        case EEventModifiersChanged:
        case EEventSwitchOn:
        case EEventPassword:
        case EEventWindowGroupsChanged:
        case EEventErrorMessage:
        case EEventPointer:
        case EEventPointerEnter:
        case EEventPointerExit:
        case EEventPointerBufferReady:
        case EEventDragDrop:
            break;
        default:
            break;
    }        
}

////////////////////////////////////////////////////////////////////////////////
//              Windows Server Event Receiver Implementation                  //
////////////////////////////////////////////////////////////////////////////////

// -----------------------------------------------------------------------------
// CWsEventReceiver::CWsEventReceiver
// Constructor.
// -----------------------------------------------------------------------------
//
CWsEventReceiver::CWsEventReceiver()
                 :CActive( CActive::EPriorityStandard ),
                  iParent( NULL )
{                      
}

// -----------------------------------------------------------------------------
// CWsEventReceiver::~CWsEventReceiver
// Destructor.
// -----------------------------------------------------------------------------
//
CWsEventReceiver::~CWsEventReceiver()
{
    Cancel();
}

// -----------------------------------------------------------------------------
// CWsEventReceiver::NewL
// Factory Function.
// -----------------------------------------------------------------------------
//
CWsEventReceiver* CWsEventReceiver::NewL( CGameController& aParent )
{
    CWsEventReceiver* self = new (ELeave) CWsEventReceiver;
    
    CleanupStack::PushL( self );
    
    self->ConstructL( aParent );
    
    CleanupStack::Pop( self );
    
    return self;    
}

// -----------------------------------------------------------------------------
// CWsEventReceiver::ConstructL
// Second phase constructor.
// Add itself to the Active Scheduler.
// -----------------------------------------------------------------------------
//
void CWsEventReceiver::ConstructL( CGameController& aParent )
{
    if( !CCoeEnv::Static() )
        User::Leave( KErrCoeEnvNotCreated );
    
    iParent = &aParent;
     
    // Register with the Windows Server for events.
    iWsSession = CCoeEnv::Static()->WsSession();
    
    iWsSession.EventReady( &iStatus );
    
    CActiveScheduler::Add( this );
    
    SetActive();
}

// -----------------------------------------------------------------------------
// CWsEventReceiver::RunL
// Is called by the Active Scheduler when a Windows
// Server event is pending.
// NOTE: This API does not leave, so RunError is not
//       implemented.
// -----------------------------------------------------------------------------
//
void CWsEventReceiver::RunL()
{
    TWsEvent wsEvent;
    iWsSession.GetEvent( wsEvent );
    
    // Pass the event on to the Game Controller.
    iParent->HandleWsEvent( wsEvent );
    
    // Request for more events.
    iWsSession.EventReady( &iStatus );
    
    SetActive();
}

// -----------------------------------------------------------------------------
// CWsEventReceiver::DoCancel
// Cancels any pending Windows Server event requests.
// -----------------------------------------------------------------------------
//
void CWsEventReceiver::DoCancel()
{
    iWsSession.EventReadyCancel();
}

extern "C" void ProcessEvents()
{
while(EFalse != iIsPause)
gameController->ProcessBackgroundTasks( ETrue );
gameController->ProcessBackgroundTasks(EFalse);
}

//from old components.cpp
s32 InitComponents(void)
{
	s32 ret;
#if defined(PSP) && defined(PSP_GPU)
  GPU_SelectPluggin(2);
#elif defined(IPHONE)
  GPU_SelectPluggin(0); // 3
#else
//  GPU_SelectPluggin(0);
#endif

	printf("CDR\n");
	ret = CDR_init();
	if (ret < 0) { SysPrintf("CDRinit error : %d", ret); return -1; }
	printf("GPU\n");
	ret = GPU_init();
	if (ret < 0) { SysPrintf("GPUinit error: %d", ret); return -1; }
	printf("SPU\n");
	ret = SPU_init();
	if (ret < 0) { SysPrintf("SPUinit error: %d", ret); return -1; }
	printf("PAD1\n");
	ret = PAD1_init(1);
	if (ret < 0) { SysPrintf("PAD1init error: %d", ret); return -1; }
	printf("PAD2\n");
	ret = PAD2_init(2);
	if (ret < 0) { SysPrintf("PAD2init error: %d", ret); return -1; }

	printf("CDR OPEN\n");
	ret = CDR_open();
	if (ret < 0) { SysPrintf("Error Opening CDR Component"); return -1; }
	printf("SPU OPEN\n");
	ret = SPU_open();
	if (ret < 0) { SysPrintf("Error Opening SPU Component"); return -1; }
	// EDIT SPU_registerCallback(SPUirq);
	printf("GPU OPEN\n");
    ret = GPU_open(0);
	//if (ret < 0) { SysPrintf("Error Opening GPU Component"); return -1; }
	printf("PAD1 OPEN\n");
	ret = PAD1_open();
	if (ret < 0) { SysPrintf("Error Opening PAD1 Component"); return -1; }
	printf("PAD2 OPEN\n");
	ret = PAD2_open();
	if (ret < 0) { SysPrintf("Error Opening PAD2 Component"); return -1; }

	return 0;
}

int SysInit() {
#ifdef GTE_DUMP
	gteLog = fopen("gteLog.txt","wb");
	setvbuf(gteLog, NULL, _IONBF, 0);
#endif

#ifdef EMU_LOG
#ifndef LOG_STDOUT
	emuLog = fopen("emuLog.txt","wb");
#else
	emuLog = stdout;
#endif
	setvbuf(emuLog, NULL, _IONBF, 0);

	SysMessage("\n--- SysInit ---\n");
	fflush(emuLog);
#endif

	psxInit();

	LoadMcds(Config.Mcd1, Config.Mcd2);

	return 0;
}

void SysReset() {
	psxReset();
}
void SysMessage(char *fmt, ...) {
	va_list list;
	char tmp[512];

	va_start(list,fmt);
	vsprintf(tmp,fmt,list);
	va_end(list);
	printf(tmp);
	printf("\n");
	//	MessageBox(0, tmp, _("Pcsx Msg"), 0);
}

void SysPrintf(char *fmt, ...) {
va_list list;
char tmp[512];

va_start(list,fmt);
vsprintf(tmp,fmt,list);
va_end(list);
printf(tmp);
printf("\n");
}
// eof
